package com.imut.lagain.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imut.lagain.config.WeChatConfig;
import com.imut.lagain.service.IWeChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 微信服务实现类
 */
@Service
public class WeChatServiceImpl implements IWeChatService {
    private static final Logger log = LoggerFactory.getLogger(WeChatServiceImpl.class);
    
    @Autowired
    private WeChatConfig weChatConfig;
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
    private static final String SUBSCRIBE_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s";
    private static final String ACCESS_TOKEN_CACHE_KEY = "wechat:access_token";
    private static final int ACCESS_TOKEN_EXPIRE_TIME = 7000; // 提前200秒过期
    
    @Override
    public Map<String, String> getSessionInfo(String code) {
        try {
            log.info("通过code获取session_key和openid: code={}", code);
            String url = String.format(JSCODE2SESSION_URL, 
                weChatConfig.getAppid(), 
                weChatConfig.getSecret(), 
                code);
            
            log.info("请求微信接口: {}", url);
            
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            log.info("微信接口响应状态码: {}, 响应内容长度: {}", response.getStatusCode(), 
                response.getBody() != null ? response.getBody().length() : 0);
            
            if (response.getBody() != null) {
                log.debug("微信接口完整响应内容: {}", response.getBody());
            }
            
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            
            Map<String, String> result = new HashMap<>();
            
            if (jsonNode.has("errcode") && jsonNode.get("errcode").asInt() != 0) {
                result.put("errcode", String.valueOf(jsonNode.get("errcode").asInt()));
                result.put("errmsg", jsonNode.get("errmsg").asText());
                log.error("code2session失败: errcode={}, errmsg={}", 
                    jsonNode.get("errcode").asInt(), jsonNode.get("errmsg").asText());
            } else {
                result.put("openid", jsonNode.get("openid").asText());
                result.put("session_key", jsonNode.get("session_key").asText());
                
                if (jsonNode.has("unionid")) {
                    result.put("unionid", jsonNode.get("unionid").asText());
                }
                
                log.info("code2session成功，openid: {}", result.get("openid"));
            }
            
            return result;
        } catch (Exception e) {
            log.error("code2session异常: ", e);
            Map<String, String> errorResult = new HashMap<>();
            errorResult.put("errcode", "-1");
            errorResult.put("errmsg", "系统异常: " + e.getMessage());
            return errorResult;
        }
    }
    
    @Override
    public Map<String, Object> decryptPhoneNumber(String encryptedData, String iv, String sessionKey) {
        try {
            log.info("解密微信手机号: encryptedData长度={}, iv长度={}, sessionKey长度={}",
                encryptedData != null ? encryptedData.length() : 0,
                iv != null ? iv.length() : 0,
                sessionKey != null ? sessionKey.length() : 0);
            
            // Base64解码
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
            byte[] ivBytes = Base64.getDecoder().decode(iv);
            byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
            
            // AES解密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(sessionKeyBytes, "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            String decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8);
            log.info("手机号解密完成，解密数据长度: {}", decryptedData.length());
            
            // 解析JSON
            JsonNode jsonNode = objectMapper.readTree(decryptedData);
            Map<String, Object> result = new HashMap<>();
            
            result.put("phoneNumber", jsonNode.get("phoneNumber").asText());
            result.put("purePhoneNumber", jsonNode.get("purePhoneNumber").asText());
            result.put("countryCode", jsonNode.get("countryCode").asText());
            
            log.info("手机号解密成功: phoneNumber={}", jsonNode.get("phoneNumber").asText());
            return result;
        } catch (Exception e) {
            log.error("解密手机号失败: ", e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("errcode", -1);
            errorResult.put("errmsg", "解密失败: " + e.getMessage());
            return errorResult;
        }
    }
    
    @Override
    public boolean sendSubscribeMessage(String openid, String templateId, Map<String, Object> data, String page) {
        try {
            log.info("发送订阅消息");
            String accessToken = getAccessTokenString();
            if (accessToken == null) {
                log.error("获取Access Token失败");
                return false;
            }
            
            String url = String.format(SUBSCRIBE_MESSAGE_URL, accessToken);
            
            Map<String, Object> messageData = new HashMap<>();
            messageData.put("touser", openid);
            messageData.put("template_id", templateId);
            messageData.put("page", page);
            messageData.put("data", data);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(messageData, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
            
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            
            if (jsonNode.has("errcode") && jsonNode.get("errcode").asInt() == 0) {
                log.info("订阅消息发送成功");
                return true;
            } else {
                log.error("订阅消息发送失败: {}", response.getBody());
                return false;
            }
        } catch (Exception e) {
            log.error("发送订阅消息异常", e);
            return false;
        }
    }
    
    @Override
    public boolean isWeChatServiceAvailable() {
        try {
            String accessToken = getAccessTokenString();
            return accessToken != null && !accessToken.isEmpty();
        } catch (Exception e) {
            log.error("检查微信服务可用性异常", e);
            return false;
        }
    }
    
    @Override
    public Map<String, Object> getServiceStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("available", isWeChatServiceAvailable());
        status.put("timestamp", System.currentTimeMillis());
        return status;
    }
    
    @Override
    public void handleMessage(HttpServletRequest request, HttpServletResponse response) {
        try {
            // 这里应该实现微信消息处理逻辑
            log.info("处理微信消息");
            response.getWriter().write("success");
        } catch (Exception e) {
            log.error("处理微信消息异常", e);
        }
    }
    
    @Override
    public Map<String, Object> getAccessToken() {
        try {
            Map<String, Object> result = new HashMap<>();
            String accessToken = getAccessTokenString();
            if (accessToken != null) {
                result.put("access_token", accessToken);
                result.put("expires_in", ACCESS_TOKEN_EXPIRE_TIME);
                result.put("success", true);
            } else {
                result.put("success", false);
                result.put("error", "获取access_token失败");
            }
            return result;
        } catch (Exception e) {
            log.error("获取Access Token失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("error", e.getMessage());
            return result;
        }
    }
    
    @Override
    public boolean verifySignature(String signature, String timestamp, String nonce) {
        try {
            String token = weChatConfig.getToken(); // 假设有getToken方法
            String[] arr = new String[]{token, timestamp, nonce};
            Arrays.sort(arr);
            
            StringBuilder content = new StringBuilder();
            for (String s : arr) {
                content.append(s);
            }
            
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes(StandardCharsets.UTF_8));
            
            StringBuilder hexStr = new StringBuilder();
            for (byte b : digest) {
                String shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            
            return hexStr.toString().equals(signature);
        } catch (Exception e) {
            log.error("验证签名失败", e);
            return false;
        }
    }
    
    @Override
    public Map<String, Object> sendTemplateMessage(Map<String, Object> messageData) {
        try {
            log.info("发送模板消息");
            String accessToken = getAccessTokenString();
            if (accessToken == null) {
                log.error("获取Access Token失败");
                Map<String, Object> result = new HashMap<>();
                result.put("errcode", -1);
                result.put("errmsg", "获取Access Token失败");
                return result;
            }
            
            String url = String.format(SUBSCRIBE_MESSAGE_URL, accessToken);
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(messageData, headers);
            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
            
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            Map<String, Object> result = new HashMap<>();
            
            if (jsonNode.has("errcode")) {
                result.put("errcode", jsonNode.get("errcode").asInt());
                if (jsonNode.has("errmsg")) {
                    result.put("errmsg", jsonNode.get("errmsg").asText());
                }
            }
            
            log.info("模板消息发送结果: {}", response.getBody());
            return result;
        } catch (Exception e) {
            log.error("发送模板消息异常", e);
            Map<String, Object> result = new HashMap<>();
            result.put("errcode", -1);
            result.put("errmsg", "发送模板消息异常: " + e.getMessage());
            return result;
        }
    }
    
    @Override
    public Map<String, Object> getUserInfo(String openid) {
        try {
            String accessToken = getAccessTokenString();
            if (accessToken == null) {
                return null;
            }
            
            String url = String.format("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN", 
                accessToken, openid);
            
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            
            if (jsonNode.has("errcode")) {
                log.error("获取用户信息失败: {}", response.getBody());
                return null;
            }
            
            Map<String, Object> userInfo = new HashMap<>();
            userInfo.put("openid", jsonNode.get("openid").asText());
            userInfo.put("nickname", jsonNode.get("nickname").asText());
            userInfo.put("sex", jsonNode.get("sex").asInt());
            userInfo.put("province", jsonNode.get("province").asText());
            userInfo.put("city", jsonNode.get("city").asText());
            userInfo.put("country", jsonNode.get("country").asText());
            userInfo.put("headimgurl", jsonNode.get("headimgurl").asText());
            
            if (jsonNode.has("unionid")) {
                userInfo.put("unionid", jsonNode.get("unionid").asText());
            }
            
            return userInfo;
        } catch (Exception e) {
            log.error("获取用户信息异常", e);
            return null;
        }
    }
    
    // 保留原有的获取accessToken字符串的方法
    private String getAccessTokenString() {
        try {
            // 先从缓存获取
            String cachedToken = (String) redisTemplate.opsForValue().get(ACCESS_TOKEN_CACHE_KEY);
            if (cachedToken != null && !cachedToken.isEmpty()) {
                return cachedToken;
            }
            
            // 缓存中没有，重新获取
            return refreshAccessToken();
        } catch (Exception e) {
            log.error("获取Access Token失败", e);
            return null;
        }
    }
    
    private String refreshAccessToken() {
        try {
            String url = String.format(ACCESS_TOKEN_URL, weChatConfig.getAppid(), weChatConfig.getSecret());
            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
            
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            
            if (jsonNode.has("access_token")) {
                String accessToken = jsonNode.get("access_token").asText();
                int expiresIn = jsonNode.get("expires_in").asInt();
                
                // 缓存到Redis，提前200秒过期
                redisTemplate.opsForValue().set(ACCESS_TOKEN_CACHE_KEY, accessToken, 
                    Math.min(expiresIn - 200, ACCESS_TOKEN_EXPIRE_TIME), TimeUnit.SECONDS);
                
                log.info("微信Access Token刷新成功，有效期: {}秒", expiresIn);
                return accessToken;
            } else {
                log.error("刷新Access Token失败: {}", response.getBody());
                return null;
            }
        } catch (Exception e) {
            log.error("刷新Access Token异常", e);
            return null;
        }
    }
}